package com.sailfish.template.infra.config;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sailfish.template.infra.exception.AppCommException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author XIAXINYU3
 * @date 2021.11.1
 */
@Slf4j
public class SqlFilterArgumentResolver implements HandlerMethodArgumentResolver {
    private final static String[] KEYWORDS = {"master", "truncate", "insert", "select"
            , "delete", "update", "declare", "alter", "drop", "sleep"};
    /**
     * 排除
     */
    private final static String[] EXCLUDE_KEYWORDS = {"lastUpdatedBy", "last_updated_by", "lastUpdateDate", "last_update_date"};

    /**
     * 判断Controller是否包含page 参数
     *
     * @param parameter 参数
     * @return 是否过滤
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(Page.class);
    }

    /**
     * @param parameter     入参集合
     * @param mavContainer  model 和 view
     * @param webRequest    web相关
     * @param binderFactory 入参解析
     * @return 检查后新的page对象
     * <p>
     * page 只支持查询 GET .如需解析POST获取请求报文体处理
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer
            , NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {

        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        String[] ascs = request.getParameterValues("ascs");
        String[] descs = request.getParameterValues("descs");
        String current = request.getParameter("current");
        String size = request.getParameter("size");
        Page page = new Page();
        if (StringUtils.isNotBlank(current)) {
            page.setCurrent(Long.parseLong(current));
        }

        if (StringUtils.isNotBlank(size)) {
            page.setSize(Long.parseLong(size));
        }

        page.setAsc(sqlInject(ascs));
        page.setDesc(sqlInject(descs));
        return page;
    }

    /**
     * SQL注入过滤
     *
     * @param str 待验证的字符串
     */
    public static String[] sqlInject(String[] str) {
        if (Objects.isNull(str) || str.length <= 0) {
            return null;
        }

        //过滤掉排除的
        String inStr = Arrays.stream(str)
                .filter(field -> !Lists.newArrayList(EXCLUDE_KEYWORDS).contains(field))
                .collect(Collectors.joining(",")).toLowerCase();

        //判断是否包含非法字符
        for (String keyword : KEYWORDS) {
            if (inStr.contains(keyword)) {
                log.error("查询包含非法字符 {}", keyword);
                throw new AppCommException(keyword + "包含非法字符");
            }
        }

        return str;
    }
}
